#include <QIcon>

#include "main_window.h"
#include "connection_factory.h"

const QString CMainWindow::sGUIName = "StegIT-2 Control";

CMainWindow::CMainWindow(QWidget* pParent) :
	QMainWindow(pParent),
	mConfModel(new CPropertiesModel()),
	mMainWidget(mConfModel, this),
	mSaveAction(new QAction(tr("&Save as File"), this)),
	mLoadAction(new QAction(tr("&Load from File"), this)),
	mExitAction(new QAction(tr("&Exit"), this)), 
	mStartAction(new QAction(tr("&Start"), this)),
	mRequestConfigAction(new QAction(tr("&Request Config"), this)),
	mSendConfigAction(new QAction(tr("&Send Config"), this)),
	mStatusBarLabel("Not connected."),
	mConnection(NULL)
{
	this->createMenu();
	this->createStatusBar();
	this->setCentralWidget(&mMainWidget);
	this->setWindowTitle(sGUIName);
	this->setWindowIcon(QIcon("icons/phone.png"));
	
	setupActions();
}

CMainWindow::~CMainWindow()
{
	if (mConnection)
	{
		CConnectionFactory::destroyClientConnection(mConnection);
	}
	delete mSendConfigAction;
	delete mRequestConfigAction;
	delete mStartAction;
	delete mExitAction;
	delete mLoadAction;
	delete mSaveAction;
	delete mConfModel;
}

void CMainWindow::connectRequested(QString pHost, quint16 pPort)
{
	mStatusBarLabel.setText("Connecting ... Please wait.");
	mConnection = CConnectionFactory::getClientConnection(pHost, pPort);
	connectConnectionBindings();
}

void CMainWindow::startRequested()
{
	mConnection->requestStart();
	mMainWidget.startRequested();
	mRequestConfigAction->setEnabled(false);
	mSendConfigAction->setEnabled(false);
	mLoadAction->setEnabled(false);
}

void CMainWindow::configRequested()
{
	mMainWidget.configRequested();
	mConnection->requestConfig();
}

void CMainWindow::sendConfigRequested()
{
	mMainWidget.sendConfigRequested(mConnection);
}

void CMainWindow::disconnectRequested()
{
	if (mConnection)
	{
		disconnectConnectionBindings();
		CConnectionFactory::destroyClientConnection(mConnection);
	}
	clientDisconnected();
	mStartAction->setEnabled(false);
	mRequestConfigAction->setEnabled(false);
	mLoadAction->setEnabled(true);
	mSendConfigAction->setEnabled(false);

	mMainWidget.getTabComm()->resetCounters();
	mMainWidget.getTabComm()->resetInfoLabels();
}

void CMainWindow::connectConnectionBindings()
{
	connect(mConnection, SIGNAL(clientConnected(QString, quint16)),
			this, SLOT(clientConnected(QString, quint16)));
	connect(mConnection, SIGNAL(clientDisconnected()),
			this, SLOT(clientDisconnected()));
	connect(mConnection, SIGNAL(connectionError(QString)),
			this, SLOT(connectionError(QString)));
	connect(mConnection, SIGNAL(infoReceived(ELogLevel, QString)),
			this, SLOT(infoReceived(ELogLevel, QString)));
	connect(mConnection, SIGNAL(closeReceived()),
			this, SLOT(closeReceived()));

	connect(mConnection, SIGNAL(extractBufferInfoReceived(quint32, quint32)),
			mMainWidget.getTabComm(), SLOT(extractBufferInfoReceived(quint32, quint32)));
	connect(mConnection, SIGNAL(frameSendLengthReceived(quint32)),
			mMainWidget.getTabComm(), SLOT(frameSendLengthReceived(quint32)));
	connect(mConnection, SIGNAL(frameRecvLengthReceived(quint32, bool)),
			mMainWidget.getTabComm(), SLOT(frameRecvLengthReceived(quint32, bool)));
	connect(mConnection, SIGNAL(packetSendLengthReceived(quint32)),
			mMainWidget.getTabComm(), SLOT(packetSendLengthReceived(quint32)));
	connect(mConnection, SIGNAL(packetRecvLengthReceived(quint32, bool)),
			mMainWidget.getTabComm(), SLOT(packetRecvLengthReceived(quint32, bool)));
	connect(mConnection, SIGNAL(streamSendInfoReceived(int, int, quint32, bool)),
			mMainWidget.getTabComm(), SLOT(streamSendInfoReceived(int, int, quint32, bool)));
	connect(mConnection, SIGNAL(streamSendDataReceived(void*, int)),
			mMainWidget.getTabComm(), SLOT(streamSendDataReceived(void*, int)));
	connect(mConnection, SIGNAL(streamRecvInfoReceived(int, int, quint32, bool)),
			mMainWidget.getTabComm(), SLOT(streamRecvInfoReceived(int, int, quint32, bool)));
	connect(mConnection, SIGNAL(streamRecvDataReceived(void*, int)),
			mMainWidget.getTabComm(), SLOT(streamRecvDataReceived(void*, int)));
	connect(mConnection, SIGNAL(protocolWriteDataReceived(void*, int)),
			mMainWidget.getTabComm(), SLOT(protocolWriteDataReceived(void*, int)));
	connect(mMainWidget.getTabComm(), SIGNAL(protocolReadDataSend(const void*, int)),
			mConnection, SLOT(protocolReadDataSend(const void*, int)));
	connect(mConnection, SIGNAL(protocolReadFeedbackReceived(quint32, quint32)),
			mMainWidget.getTabComm(), SLOT(protocolReadFeedbackReceived(quint32, quint32)));
	connect(mConnection, SIGNAL(embedAmpReceived(quint8)),
			mMainWidget.getTabComm(), SLOT(embedAmpReceived(quint8)));
	connect(mConnection, SIGNAL(extractAmpReceived(quint8)),
			mMainWidget.getTabComm(), SLOT(extractAmpReceived(quint8)));

	connect(mMainWidget.getTabDefense(), SIGNAL(sendDefenseValue(quint32)),
			mConnection, SLOT(sendDefenseValue(quint32)));

	connect(mConnection, SIGNAL(configReceived(const QString&, const QString&, const QString&)),
			mConfModel, SLOT(configReceived(const QString&, const QString&, const QString&)));
	connect(mConnection, SIGNAL(configReceivedEnd()),
			mMainWidget.getTabConf(), SLOT(configReceivedEnd()));
}

void CMainWindow::disconnectConnectionBindings()
{
	disconnect(mConnection, SIGNAL(clientConnected(QString, quint16)),
			this, SLOT(clientConnected(QString, quint16)));
	disconnect(mConnection, SIGNAL(clientDisconnected()),
			this, SLOT(clientDisconnected()));
	disconnect(mConnection, SIGNAL(connectionError(QString)),
			this, SLOT(connectionError(QString)));
	disconnect(mConnection, SIGNAL(infoReceived(ELogLevel, QString)),
			this, SLOT(infoReceived(ELogLevel, QString)));
	disconnect(mConnection, SIGNAL(closeReceived()),
			this, SLOT(closeReceived()));

	disconnect(mConnection, SIGNAL(extractBufferInfoReceived(quint32, quint32)),
			mMainWidget.getTabComm(), SLOT(extractBufferInfoReceived(quint32, quint32)));
	disconnect(mConnection, SIGNAL(frameSendLengthReceived(quint32)),
			mMainWidget.getTabComm(), SLOT(frameSendLengthReceived(quint32)));
	disconnect(mConnection, SIGNAL(frameRecvLengthReceived(quint32, bool)),
			mMainWidget.getTabComm(), SLOT(frameRecvLengthReceived(quint32, bool)));
	disconnect(mConnection, SIGNAL(packetSendLengthReceived(quint32)),
			mMainWidget.getTabComm(), SLOT(packetSendLengthReceived(quint32)));
	disconnect(mConnection, SIGNAL(packetRecvLengthReceived(quint32, bool)),
			mMainWidget.getTabComm(), SLOT(packetRecvLengthReceived(quint32, bool)));
	disconnect(mConnection, SIGNAL(streamSendInfoReceived(int, int, quint32, bool)),
			mMainWidget.getTabComm(), SLOT(streamSendInfoReceived(int, int, quint32, bool)));
	disconnect(mConnection, SIGNAL(streamSendDataReceived(void*, int)),
			mMainWidget.getTabComm(), SLOT(streamSendDataReceived(void*, int)));
	disconnect(mConnection, SIGNAL(streamRecvInfoReceived(int, int, quint32, bool)),
			mMainWidget.getTabComm(), SLOT(streamRecvInfoReceived(int, int, quint32, bool)));
	disconnect(mConnection, SIGNAL(streamRecvDataReceived(void*, int)),
			mMainWidget.getTabComm(), SLOT(streamRecvDataReceived(void*, int)));
	disconnect(mConnection, SIGNAL(protocolWriteDataReceived(void*, int)),
			mMainWidget.getTabComm(), SLOT(protocolWriteDataReceived(void*, int)));
	disconnect(mMainWidget.getTabComm(), SIGNAL(protocolReadDataSend(const void*, int)),
			mConnection, SLOT(protocolReadDataSend(const void*, int)));
	disconnect(mConnection, SIGNAL(protocolReadFeedbackReceived(quint32, quint32)),
			mMainWidget.getTabComm(), SLOT(protocolReadFeedbackReceived(quint32, quint32)));
	disconnect(mConnection, SIGNAL(embedAmpReceived(quint8)),
			mMainWidget.getTabComm(), SLOT(embedAmpReceived(quint8)));
	disconnect(mConnection, SIGNAL(extractAmpReceived(quint8)),
			mMainWidget.getTabComm(), SLOT(extractAmpReceived(quint8)));

	disconnect(mMainWidget.getTabDefense(), SIGNAL(sendDefenseValue(quint32)),
			mConnection, SLOT(sendDefenseValue(quint32)));

	disconnect(mConnection, SIGNAL(configReceived(const QString&, const QString&, const QString&)),
			mConfModel, SLOT(configReceived(const QString&, const QString&, const QString&)));
	disconnect(mConnection, SIGNAL(configReceivedEnd()),
			mMainWidget.getTabConf(), SLOT(configReceivedEnd()));
}

void CMainWindow::clientConnected(QString pHost, quint16 pPort)
{
	mStatusBarLabel.setText("Connected to " + pHost + ":" + QString::number(pPort, 10));
	mMainWidget.clientConnected(pHost, pPort);
	mStartAction->setEnabled(true);
	mRequestConfigAction->setEnabled(true);
	mSendConfigAction->setEnabled(true);
}

void CMainWindow::clientDisconnected()
{
	mStatusBarLabel.setText("Not connected.");
	mMainWidget.clientDisconnected();
	mStartAction->setEnabled(false);
	mRequestConfigAction->setEnabled(false);
	mSendConfigAction->setEnabled(false);
	mLoadAction->setEnabled(true);
}

void CMainWindow::connectionError(QString pErrorMsg)
{
	QString lErrorMsg("Error: ");
	mStatusBarLabel.setText(lErrorMsg + pErrorMsg);
	mMainWidget.connectionError();
	disconnectConnectionBindings();
}

void CMainWindow::infoReceived(ELogLevel pLogLevel, QString pLogMessage)
{
	mMainWidget.infoReceived(pLogLevel, pLogMessage);
}

void CMainWindow::closeReceived()
{
	/* tbd */
}

void CMainWindow::saveToFile()
{
	QString lFilename = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Configuration Files (*.conf)"));
	if (!lFilename.isEmpty())
	{
		mMainWidget.saveToFile(lFilename);
	}
}

void CMainWindow::loadFromFile()
{
	QString lFilename = QFileDialog::getOpenFileName(this, tr("Open Configuration File"), "", tr("Configuration Files (*.conf)"));
	if (!lFilename.isEmpty())
	{
		mMainWidget.loadFromFile(lFilename);
	}
}

void CMainWindow::setupActions()
{
	connect(this->mMainWidget.getConnectionWidget(), SIGNAL(connectRequested(QString, quint16)),
			this, SLOT(connectRequested(QString, quint16)));
	connect(this->mMainWidget.getConnectionWidget(), SIGNAL(disconnectRequested()),
			this, SLOT(disconnectRequested()));
	connect(this->mMainWidget.getConnectionWidget(), SIGNAL(startRequested()),
			this, SLOT(startRequested()));
}

void CMainWindow::createMenu()
{
	mSaveAction->setShortcut(tr("Ctrl+S"));
	mLoadAction->setShortcut(tr("Ctrl+O"));
	mExitAction->setShortcut(tr("Ctrl+Q"));
	connect(mSaveAction, SIGNAL(triggered()), this, SLOT(saveToFile()));
	connect(mLoadAction, SIGNAL(triggered()), this, SLOT(loadFromFile()));
	connect(mExitAction, SIGNAL(triggered()), this, SLOT(close()));
	mFileMenu = menuBar()->addMenu(tr("&File"));
	mFileMenu->addAction(mSaveAction);
	mFileMenu->addAction(mLoadAction);
	mFileMenu->addSeparator();
	mFileMenu->addAction(mExitAction);
	mCommandsMenu = menuBar()->addMenu(tr("&Commands"));
	mCommandsMenu->addAction(mStartAction);
	mCommandsMenu->addAction(mRequestConfigAction);
	mCommandsMenu->addAction(mSendConfigAction);
	connect(mStartAction, SIGNAL(triggered()), this, SLOT(startRequested()));
	connect(mRequestConfigAction, SIGNAL(triggered()), this, SLOT(configRequested()));
	connect(mSendConfigAction, SIGNAL(triggered()), this, SLOT(sendConfigRequested()));
	mStartAction->setEnabled(false);
	mRequestConfigAction->setEnabled(false);
	mSendConfigAction->setEnabled(false);
	mLoadAction->setEnabled(true);
	mSaveAction->setEnabled(true);
}

void CMainWindow::createStatusBar()
{
	mStatusBarLabel.setAlignment(Qt::AlignHCenter);
	mStatusBarLabel.setMinimumSize(mStatusBarLabel.sizeHint());
	statusBar()->addWidget(&mStatusBarLabel);
}

